package com.atldy.commerce.filter;

import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @version 1.0
 * @Author: li-dong-yang
 * @CreateTime: 2021-09-12 9:16
 * @Description： 过滤器 初始化 Hystrix 请求上下文环境
 */
@Slf4j
@WebFilter(
        filterName = "HystrixRequestContextServletFilter",
        urlPatterns = "/*",
        asyncSupported = true
)
public class HystrixRequestContextServletFilter implements Filter {

    /**
     * <h3>初始化hystrix请求上下文路径</h3>
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        log.info(" >>>>>>>>>开启过滤器初始化hystrix请求上下文路径<<<<<<");
        // 初始化 Hystrix 请求上下文
        // 在不同的 context 中缓存是不共享的
        // 这个初始化是必须的
        HystrixRequestContext initializeContext = HystrixRequestContext.initializeContext();

        try {
            hystrixConcurrencyStrategyConfig();
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            initializeContext.shutdown();
        }

    }

    /**
     * <h3>配置 Hystrix 的并发策略</h3>
     */
    private void hystrixConcurrencyStrategyConfig() {
        try {
            //hystrix并发策略
            HystrixConcurrencyStrategy strategy = HystrixConcurrencyStrategyDefault.getInstance();
            //获取当前hystrix的并发策略
            HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (concurrencyStrategy instanceof HystrixConcurrencyStrategy) {
                //    如果是想要配置的
                return;
            }
            // 将原来其他的配置保存下来
            HystrixCommandExecutionHook commandExecutionHook =
                    HystrixPlugins.getInstance().getCommandExecutionHook();
            HystrixEventNotifier eventNotifier =
                    HystrixPlugins.getInstance().getEventNotifier();
            HystrixMetricsPublisher metricsPublisher =
                    HystrixPlugins.getInstance().getMetricsPublisher();
            HystrixPropertiesStrategy propertiesStrategy =
                    HystrixPlugins.getInstance().getPropertiesStrategy();

            // 先重置, 再把我们自定义的配置与原来的配置写回去
            HystrixPlugins.reset();
            HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);
            HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
            HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
            HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
            HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);

            log.info("config hystrix concurrency strategy success");
        } catch (Exception e) {
            log.error("Failed to register Hystrix Concurrency Strategy: [{}]",
                    e.getMessage(), e);
        }
    }
}